﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class SceneryLayer : MonoBehaviour {
	//滚动速度
	public float parallaxSpeed = 1.0f;  
	//是否无限添加元素块
	public bool isInfinite = true;
	//最大元素块数
	public int maxBlockCount = 0;
	//下一个要显示层
	public SceneryLayer nextLayer = null;
	//屏幕左边缘
	private float ScreenLeftEdge;
	//屏幕右边缘
	private float ScreenRightEdge;
	//所有元素块池
	private List<SceneryBlock> blockSpool;
	//要显示的元素块池
	private List<SceneryBlock> visibleBlocks;

	//隐藏区域
	private GameObject inactiveBlocks;
	//显示区域
	private GameObject activeBlocks;
	//是否可以创建元素块
	private bool blockCreationEnabled = true;
	//已经创建了多少元素块
	private int numBlocksCreated = 0;


	void Start()
	{
		ScreenRightEdge = Camera.main.aspect * Camera.main.orthographicSize;
		ScreenLeftEdge = -ScreenRightEdge;

		if (!isInfinite)
			DisableNextLayer ();

		activeBlocks = new GameObject ("ActiveBlocks");
		inactiveBlocks = new GameObject ("InactiveBlocks");
		activeBlocks.transform.parent = transform;
		inactiveBlocks.transform.parent = transform;

		inactiveBlocks.SetActive (false);
		InitBlockPool ();

	}
	/// <summary>
	/// Restart this instance.
	/// </summary>
	public void Restart()
	{
		numBlocksCreated = 0;
		blockCreationEnabled = true;

		List<SceneryBlock> allActive = new List<SceneryBlock> ();
		foreach (SceneryBlock block in visibleBlocks)
			allActive.Add (block);
		foreach (SceneryBlock block in allActive)
			RemoveVisibleBlock (block);
	}
	/// <summary>
	/// 初始化元素块池
	/// </summary>
	private void InitBlockPool()
	{
		blockSpool = new List<SceneryBlock> ();
		visibleBlocks = new List<SceneryBlock> ();

		SceneryBlock[] blocks = GetComponentsInChildren<SceneryBlock> ();

		for (int i = 0; i < blocks.Length; i++)
		{
			blockSpool.Add (blocks[i]);
			blocks [i].transform.parent = inactiveBlocks.transform;
		}
	}
	/// <summary>
	/// Disables the next layer.
	/// </summary>
	public void DisableNextLayer()
	{
		if (!isInfinite)
		{
			if (nextLayer == null)
				Debug.LogWarning ("Layer " + this.name + "is finite but has no nextLayer set. Player could reach the edge of the world");
			else
				nextLayer.DisableBlockCreation ();
		}
	}
	//可创建元素块
	private void EnableBlockCreation(float startX)
	{
		blockCreationEnabled = true;
		numBlocksCreated = 0;

		GenerateNewBlocks (startX);
	}
	/// <summary>
	/// 生成新的元素块
	/// </summary>
	/// <param name="blockX">Block x.</param>
	private void GenerateNewBlocks(float blockX)
	{
		while (blockCreationEnabled && blockX < ScreenRightEdge)
		{
			if (isInfinite || numBlocksCreated < maxBlockCount) {
				SceneryBlock block = AddNewBlock (new Vector2 (blockX, 0.0f));
				if (block == null)
					break;

				blockX += block.width;
			} else {
				StartNextLayer (blockX);
			}
		}
	}

	/// <summary>
	/// 不可创建元素块
	/// </summary>
	private void DisableBlockCreation ()
	{
		blockCreationEnabled = false;
	}

	/// <summary>
	/// 开始生成下一个显示层
	/// </summary>
	/// <param name="startX">Start x.</param>
	private void StartNextLayer(float startX)
	{
		DisableBlockCreation ();
		if (nextLayer != null)
			nextLayer.EnableBlockCreation (startX);
	}
	/// <summary>
	/// 添加元素块
	/// </summary>
	/// <returns>The new block.</returns>
	/// <param name="position">Position.</param>
	SceneryBlock AddNewBlock(Vector2 position)
	{
		if (blockSpool.Count == 0)
		{
			Debug.LogWarning ("Not enough blocks in layer" + this.name);
			return null;
		}
		int idx = Random.Range (0, blockSpool.Count);
		SceneryBlock block = blockSpool [idx];

		position.x += block.width / 2;
		block.transform.position = position;

		blockSpool.Remove (block);
		visibleBlocks.Add (block);
		block.transform.parent = activeBlocks.transform;

		numBlocksCreated++;

		return block;
	}
	/// <summary>
	/// 元素块活动控制
	/// </summary>
	/// <param name="scrollSpeed">Scroll speed.</param>
	public void UpdateBlocks(float scrollSpeed)
	{
		float dT = Time.deltaTime;
		float blockX = ScreenLeftEdge;
		List<SceneryBlock> offscreen = new List<SceneryBlock> ();

		for(int i = 0; i < visibleBlocks.Count; i++)
		{
			Vector3 position = visibleBlocks [i].transform.position;
			position.x -= scrollSpeed * parallaxSpeed * dT;
			visibleBlocks [i].transform.position = position;

			float blockRightEdge = position.x + visibleBlocks [i].width / 2;
			blockX = Mathf.Max (blockX, blockRightEdge);

			bool fullyOffScreen = blockRightEdge < ScreenLeftEdge;
			if (fullyOffScreen)
				offscreen.Add (visibleBlocks[i]);
		}

		for(int i = 0; i < offscreen.Count; i++)
		{
			RemoveVisibleBlock(offscreen[i]);
		}

		if(blockX < ScreenRightEdge)
			GenerateNewBlocks(blockX);
	}
	/// <summary>
	/// Removes the visible block.
	/// </summary>
	/// <param name="block">Block.</param>
	void RemoveVisibleBlock(SceneryBlock block)
	{
		block.transform.parent = inactiveBlocks.transform;
		visibleBlocks.Remove (block);
		blockSpool.Add (block);
	}
}
